/***********************************************************************
 * Module:  ModeleCarteDrawer.java
 * Author:  Fabien Muguet
 * Purpose: Defines the Class CartePostaleDrawer
 ***********************************************************************/

package vue.composants;

import modele.*;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.event.MouseInputListener;
import main.Outils;
import modele.Image;
import vue.EcranPosition;


public class EcranPositionCPD extends CartePostaleDrawer implements MouseInputListener {

    // Référence vers l'écran
    private EcranPosition ecran;

    // Références vers les zones d'images dans le modèle
    private ZoneImage[] zonesImg;

    // Equivalent Rectangle pour simplifier les calculs
    private Rectangle[] zonesRect;

    // Zone survolée, pour surbrillance
    private int zoneSurvolee;

    // En train de drag and drop
    private boolean dragAndDrop;

    // Image de fond en cache
    private Image imageDeFond;


    public EcranPositionCPD(Ressources ressources, EcranPosition ecran, CartePostale cartePostale, String etapeCreation, Dimension dimension) {

        super(ressources, cartePostale, etapeCreation, dimension);
        
        // On garde la référence vers l'écran
        this.ecran = ecran;

        zonesImg = ressources.getCartePostale().getModele().getZoneImage();
        zonesRect = new Rectangle[ zonesImg.length ];
        for(int i = 0; i < zonesImg.length; i++) {
            zonesRect[i] = new Rectangle(
                    (int)(zonesImg[i].getPosX() * facteur),
                    (int)(zonesImg[i].getPosY() * facteur),
                    (int)(zonesImg[i].getWidth() * facteur),
                    (int)(zonesImg[i].getHeight() * facteur)
            );
        }

        // Init des infos de drag and drop
        zoneSurvolee = -1;
        dragAndDrop = false;

        // On s'écoute pour pouvoir supprimer les images avec un clic
        addMouseListener(this);
        addMouseMotionListener(this);

        // On travaille l'image de fond une fois pour toute
        imageDeFond = null;
        Image imageDeFondRessource = ressources.getCartePostale().getImageDeFond();
        if( imageDeFondRessource != null ) {

            // Si besoin on restaure le fond
            if( imageDeFondRessource.estEnregistreeEnMemoire() )
                imageDeFondRessource.chargerDepuisMemoire();

            // On travaille l'image pour pouvoir l'appliquer au fond
            imageDeFond = new Image(null,null,null,null);

            // On adapte l'image de fond au type de cadre (Portrait ou Paysage)
            if((ressources.getCartePostale().getModele().getOrientation()==ModeleCarte.Orientation.PAYSAGE)&&(imageDeFondRessource.getImage().getWidth()<imageDeFondRessource.getImage().getHeight()))
            {
                // Dimension a adapter en paysage
                int temp = dimension.height;
                dimension.height = dimension.width;
                dimension.width = temp;
                // EN COURS DE CODAGE
                 imageDeFond.setImage(
                    Outils.etirer(
                        imageDeFondRessource.getImage(),
                        dimension
                    )
                );
            }
            else if((ressources.getCartePostale().getModele().getOrientation()==ModeleCarte.Orientation.PORTRAIT)&&(imageDeFondRessource.getImage().getWidth()<imageDeFondRessource.getImage().getHeight()))
            {
                // Dimension en portrait
                imageDeFond.setImage(
                    Outils.ajuster(
                        imageDeFondRessource.getImage(),
                        dimension
                    )
                );
            }
            else if((ressources.getCartePostale().getModele().getOrientation()==ModeleCarte.Orientation.PORTRAIT)&&(imageDeFondRessource.getImage().getWidth()>imageDeFondRessource.getImage().getHeight()))
            {
                //Dimension a adapter en portrait
                int temp = dimension.height;
                dimension.height = dimension.width;
                dimension.width = temp;
                // EN COURS DE CODAGE
                imageDeFond.setImage(
                    Outils.etirer(
                        imageDeFondRessource.getImage(),
                        dimension
                    )
                );
            }
            else
            {
                //DImension en paysage
                   imageDeFond.setImage(
                    Outils.ajuster(
                        imageDeFondRessource.getImage(),
                        dimension
                    )
                );
            }
           

            // On libère la mémoire
            imageDeFondRessource.enregistrerEnMemoire();

        }

    }


    /**
     * Retourne l'identifiant de la zone contenant le point p.
     * Si aucune zone ne contient le point alors on retourne -1;
     *
     * @param p Le point donné
     * @return L'identifiant de la zone, ou alors -1 si non trouvé
     */
    private int zoneContientPoint(Point p) {

        for(int i = 0; i < zonesRect.length; i++) {
            if(zonesRect[i].contains(p))
                return i;
        }

        return -1;
    }


    /**
     * Dessin du CPD.
     *
     * @param g Contexte graphique.
     */
    public void paintComponent(Graphics g) {

        Graphics2D g2d = (Graphics2D)g;
        int i, x, y, w, h;


        // ------------------------------
        // Dessin du fond
        // ------------------------------

        // On regarde s'il y a une image ou une couleur de fond
        if( imageDeFond != null ) {
            g.drawImage(imageDeFond.getImage(), 0, 0, null);
        } else {
            g.setColor( ressources.getCartePostale().getCouleurDeFond() );
            g.fillRect(0, 0, width, height);
        }

        // Dessin d'une bordure
        g.setColor(Color.BLACK);
        g.drawRect(0, 0, width, height);


        // ------------------------------
        // Dessin des zones d'image
        // ------------------------------

        // On récupère la zone de texte à afficher
        ZoneImage zImage[] = cartePostale.getModele().getZoneImage();

        // Couleur des zones
        Color coulFondZone = Color.WHITE;
        Color coulBordZone = new Color(150, 150, 150);
        Color coulFondZoneSurbrillance = new Color(255, 255, 150);
        Color coulBordZoneSurbrillance = new Color(200, 200, 50);

        // On boucle pour chaque zone
        for(i=0; i < zImage.length; i++) {

            // On redimensionne les coordonnées à l'échelle
            x = redim(zImage[i].getPosX());
            y = redim(zImage[i].getPosY());
            w = redim(zImage[i].getWidth());
            h = redim(zImage[i].getHeight());

            /* T0D0 : prise en compte des rotations */

            // On regarde si la zone est occupée par une image, ou survolée
            ImageSurZone imageSurLaZone = null;
            ImageSurZone[] imagesSurZones = ressources.getCartePostale().getImagesSurZones();
            if( imagesSurZones != null ) {
                for (int j = 0; j < imagesSurZones.length && imageSurLaZone == null; j++) {
//                    System.out.println("zImage[i] =  " + zImage[i] + " - imagesSurZones[j].getZone() = " + imagesSurZones[j].getZone() );
                    if( imagesSurZones[j] != null && zImage[i] == imagesSurZones[j].getZone() ) {
                        imageSurLaZone = imagesSurZones[j];
                    }
                }
            }
            
            
            if( imageSurLaZone != null ) {
                /* Il y a une image sur la zone */
                
                // On la redimensionne
                BufferedImage mini = Outils.homothetie(imageSurLaZone.getImage().getImageOuMiniature(), facteur);
                mini = Outils.ajuster(mini, new Dimension(w,h) );

                // On la dessine
                g.drawImage(mini, x, y, null);

                // Si survol de la
                if( !dragAndDrop && i == zoneSurvolee ) {

                    Color couleurFiltre = new Color(255, 255, 255);

                    // Dessin du rectangle
                    g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f ));
                    g2d.setColor(couleurFiltre);
                    g2d.fillRect(x, y, w, h);

                    // On rajoute un picto image et un chiffre par dessus
                    BufferedImage pictoSupprimer = ressources.getPictoSupprimer();
                    if( pictoSupprimer != null ) {
                        
                        x += (w - pictoSupprimer.getWidth())/2;
                        y += (h - pictoSupprimer.getHeight())/2;

                        // Picto image
                        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f ));
                        g.drawImage(pictoSupprimer, x, y, this);
                        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f ));
                    }
                }
                
            } else if( dragAndDrop && i == zoneSurvolee ) {
                /* Zone vide survolée par un drag and drop */

                // Dessin du rectangle
                g.setColor(coulFondZoneSurbrillance);
                g.fillRect(x, y, w, h);
                g.setColor(coulBordZoneSurbrillance);
                g.drawRect(x, y, w, h);

                // Ajout d'un texte "poser ici"
                x += w/2 - 2;
                y += h/2 + 10;

                String texte = "Poser ici";
                Font font = new Font("Verdana", Font.BOLD, 14);
                Color couleur = new Color(65, 95, 140);

                // On détermine la taille du texte pour pouvoir centrer
                FontMetrics metrics = new FontMetrics(font) {};
                Rectangle2D bounds = metrics.getStringBounds(texte, null);
                int widthInPixels = (int)bounds.getWidth();
                int heightInPixels = (int)bounds.getHeight();

                // On écrit le texte centré
                g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f ));
                g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                g2d.setFont(font);
                g2d.setColor( couleur );
                g2d.drawString(texte, x-(widthInPixels/2), y-(heightInPixels/2));

            } else {
                /* Zone vide non survolée  */

                // Dessin du rectangle
                g.setColor(coulFondZone);
                g.fillRect(x, y, w, h);
                g.setColor(coulBordZone);
                g.drawRect(x, y, w, h);
            
                // On rajoute un picto image et un chiffre par dessus
                BufferedImage pictoImage = ressources.getPictoImage();
                if( pictoImage != null ) {
                    x += (w - pictoImage.getWidth())/2;
                    y += (h - pictoImage.getHeight())/2;

                    Font font = new Font("Verdana", Font.BOLD, 14);

                    // Picto image
                    g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f ));
                    g.drawImage(pictoImage, x, y, this);

                    // Chiffre
                    g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f ));
                    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                    g2d.setFont(font);
                    g2d.setColor( new Color(65, 95, 140) );
                    g2d.drawString( new Integer(i+1).toString() , x+7, y+30);
                }
            }

        }


        // ------------------------------
        // Dessin du texte
        // ------------------------------

        // On récupère la zone de texte à afficher
        ZoneTexte zTexte = cartePostale.getModele().getZoneTexte();

        // Texte, police et couleur du texte
        String texte = "<Votre texte ici>";
        Font font = new Font("Verdana", Font.PLAIN, redim(zTexte.getTailleFont()));
        g2d.setColor(Color.BLACK);

        // On redimensionne la coordonnée à l'échelle
        x = redim(zTexte.getPosX());
        y = redim(zTexte.getPosY());

        // On détermine la taille du texte pour pouvoir centrer
        FontMetrics metrics = new FontMetrics(font) {};
        Rectangle2D bounds = metrics.getStringBounds(texte, null);
        int widthInPixels = (int)bounds.getWidth();
        int heightInPixels = (int)bounds.getHeight();

        // On écrit le texte centré
        g2d.setFont(font);
        g2d.drawString(texte, x-(widthInPixels/2), y-(heightInPixels/2));

    }


    /**
     * Vérifie la validité de l'étape de création fournie.
     *
     * @param etapeCreation L'étape de création
     * @return true si l'étape existe, false sinon
     */
    public boolean verifEtapeCreation(String etapeCreation) {
        return (etapeCreation == "position");
    }



    // Début du glissé-déposé
    public void mousePressed(MouseEvent e) {

        // Seulement si l'on vient d'une miniature
        if( e.getSource() != this ) {

            // Début du DND
            ecran.dndDebut();
            dragAndDrop = true;
        }
    }

    // Fin du glissé-déposé
    public void mouseReleased(MouseEvent e) {

        // Uniquement pour fin de drag and drop
        if( dragAndDrop ) {

            // Fin du DND
            ecran.dndFin();
            zoneSurvolee = -1;

            // On transfère dans le bon système de coordonnées
            Point pSrc = e.getLocationOnScreen();
            Point pDest =  getLocationOnScreen();
            int dX = pSrc.x - pDest.x;
            int dY = pSrc.y - pDest.y;
            Point p = new Point(dX, dY);

            // On redéssine
            for(int i = 0; i < zonesRect.length; i++)
                repaint(zonesRect[i]);

            // On regarde si l'on a bien attérit dans une zone d'image
            int zoneId = zoneContientPoint(p);
            if( zoneId != -1 ) {

                // On regarde sur la zone est libre
                boolean zoneLibre = true;
                ImageSurZone[] imgSurZones =  ressources.getCartePostale().getImagesSurZones();
                if( imgSurZones != null ) {
                    for (int i = 0; i < imgSurZones.length && zoneLibre; i++) {
                        if( imgSurZones[i] != null && imgSurZones[i].getZone() == zonesImg[zoneId])
                            zoneLibre = false;
                    }
                }

                // Si non libre, on quitte
                if( !zoneLibre )
                    return;

                // On récupère l'image à l'origine du glissé déposé
                EcranPositionMiniature epm = (EcranPositionMiniature)e.getSource();
                Image imageDeplacee = epm.getImage();

                // On récupère la zone de destination
                ZoneImage zoneDestination = zonesImg[zoneId];

                // On envoi l'évennement à l'écran
                ecran.dragAndDropPerformed(imageDeplacee, zoneDestination);
            }

            // Fin du drag and drop
            dragAndDrop = false;

        } else {

            // On regarde si l'on a attérit dans une zone
            zoneSurvolee = zoneContientPoint( e.getPoint() );
            if( zoneSurvolee != -1 ) {

                // On regarde si la zone contient une image
                boolean trouve = false;
                ImageSurZone[] imagesSurZones = ressources.getCartePostale().getImagesSurZones();
                if( imagesSurZones != null ) {
                    for (int j = 0; j < imagesSurZones.length && !trouve; j++) {

                        // On a trouvé la zone sur laquelle le clic à attérit
                        if( imagesSurZones[j] != null && zonesImg[ zoneSurvolee ] == imagesSurZones[j].getZone() ) {

                            // On ne cherche plus
                            trouve = true;

                            // On demande une confirmation
                            boolean confirm = ecran.afficherMessageConfirmation("Voulez-vous retirer cette image ?");
                            if(confirm) {

                                // Confirmation ok, on supprime
                                imagesSurZones[j] = null;

                                // Pour re-griser le bouton "Suivant"
                                ecran.initialiser();
                            }
                        }
                    }
                }
            }
        }

    }

    // Glissé-déposé en cours
    public void mouseDragged(MouseEvent e) {

        // Le drag and drop n'est effectif que pour les miniatures
        if( dragAndDrop ) {
            // On transfère dans le bon système de coordonnées
            Point pSrc = e.getLocationOnScreen();
            Point pDest =  getLocationOnScreen();
            int dX = pSrc.x - pDest.x;
            int dY = pSrc.y - pDest.y;
            Point p = new Point(dX, dY);

            // On regarde si l'on a bien attérit dans une zone d'image
            zoneSurvolee = zoneContientPoint(p);

            // On redéssine
            for(int i = 0; i < zonesRect.length; i++)
                repaint(zonesRect[i]);
        }
    }

    // Survol sans drag and drop : possibilité de suppression
    public void mouseMoved(MouseEvent e) {

        // Pas utile pour le drag and drop
        if( e.getSource() == this ) {

            // On regarde si l'on a bien attérit dans une zone d'image
            zoneSurvolee = zoneContientPoint( e.getPoint() );

            // On met le curseur par défaut
            setCursor( Cursor.getDefaultCursor() );

            if( zoneSurvolee != -1 ) {
            // On regarde si l'on a attérit dans une zone

                // On regarde si la zone contient une image
                boolean trouve = false;
                ImageSurZone[] imagesSurZones = ressources.getCartePostale().getImagesSurZones();
                if( imagesSurZones != null ) {
                    for (int j = 0; j < imagesSurZones.length && !trouve; j++) {

                        // On a trouvé la zone sur laquelle le clic à attérit
                        if( imagesSurZones[j] != null && zonesImg[ zoneSurvolee ] == imagesSurZones[j].getZone() ) {

                            // On ne cherche plus
                            trouve = true;

                            // On change le curseur
                            setCursor( Cursor.getPredefinedCursor( Cursor.HAND_CURSOR ));
                        }
                    }
                }
            }

            // On redéssine
            for(int i = 0; i < zonesRect.length; i++)
                repaint(zonesRect[i]);
        }
    }


    // Pour implémentation
    public void mouseClicked(MouseEvent e) { }
    public void mouseEntered(MouseEvent e) { }
    public void mouseExited(MouseEvent e) { }

}